/* -+- file  ./kf2/Roster/Item.cs -+- */
/*
 * kf2 jabber client
 * ~~~~~~~~~~~~~~~~~
 *
 * Copyright (C) 2006-2007 Przemysław Sitek
 * 				<przemyslaw.sitek at wp.pl> 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
using System;
using System.Collections.Generic;
using Habazie.kf2.Core;
using Habazie.kf2.Net;

namespace Habazie.kf2.Roster
{
	
	public class Item : Habazie.kf2.GUI.IRosterItem
	{
		#region Private fields
		
		///<summary>Jabber ID of a contact</summary>
		private jabber.JID m_JID = null;
		
		///<summary>Contact name</summary>
		private string m_Name = null;
		
		///<summary>Contact subscription</summary>
		private jabber.protocol.iq.Subscription m_Sub = jabber.protocol.iq.Subscription.none;
		
		///<summary>List of groups</summary>
		private LinkedList<string> m_Groups;
		
		///<summary>Resources</summary>
		private LinkedList<Resource> m_Resources;
		
		///<summary>Account</summary>
		private Account m_Account					= null;
		
		/* VCard && avatar */
		
		///<summary>Contact info</summary>
		private jabber.protocol.iq.VCard m_VCard	= null;
		
		///<summary>User avatar</summary>
		private Avatar m_Avatar						= null;
		
//		private -
		
		#endregion
		#region Events
		
		public event StatusChangedEventHandler StatusChanged = null;
		public event EventHandler InformationChanged = null;
		
		#endregion
		#region Constructors
		
		public Item()
		{
			m_Groups = new LinkedList<string> ();
			m_Resources = new LinkedList<Resource> ();
//			m_Avatar = new Avatar (
		}
		
		public Item (jabber.protocol.iq.Item item) : this ()
		{
			Assign (item);
		}
		
		#endregion
		#region Properties
		
		
		/// <summary>
		/// 	JabberID of contact
		/// </summary>
		public jabber.JID JabberID {
			get { return m_JID; }
			set { m_JID = value; }
		}
		
		
		/// <summary>
		/// 	Contact name
		/// </summary>
		public string Name {
			get { return (m_Name != null && m_Name.Length > 0) ? m_Name : m_JID.User; }
			set { m_Name = value; }
		}
		
		
		/// <summary>
		/// 	Most important resource
		/// </summary>
		public Habazie.kf2.Roster.Resource Resource {
			get { 
				if (m_Resources.Count > 0)
					return m_Resources.First.Value;
				else
					return null;
			}
		}
		
		
		/// <summary>
		/// 	Account related to this contact
		/// </summary>
		public Habazie.kf2.Net.Account Account {
			get { return m_Account; }
			set { m_Account = value; }
		}
		
		
		/// <summary>
		/// 	Groups this contact belong to
		/// </summary>
		public ICollection<string> Groups {
			get { return m_Groups; }
		}
		
		
		/// <summary>
		/// 	Number of groups this contact belong to
		/// </summary>
		public int GroupsCount {
			get { return m_Groups.Count; }
		}
		
		
		/// <summary>
		/// 	List of resources
		/// </summary>
		public ICollection<Resource> Resources {
			get { return m_Resources; }
		}
		
		
		/// <summary>
		/// 	Contact subscription
		/// </summary>
		public jabber.protocol.iq.Subscription Sub {
			get { return m_Sub; }
		}
		
		
		///<summary>
		///	Test whether item is online
		///</summary>
		public bool Available {
			get {
				foreach (Resource r in m_Resources)
					if (r.Presence == jabber.protocol.client.PresenceType.available)
						return true;
				return false;
			}
		}
		
		#endregion
		#region Methods
		
		/// <summary>
		/// 	Test whether item belongs to group
		/// </summary>
		public bool InGroup (string name)
		{
			return m_Groups.Contains (name);
		}
		
		public void Assign (jabber.protocol.iq.Item item)
		{
			/* Set some properties */
			m_JID = item.JID;
			m_Name = item.Nickname;
			m_Sub = item.Subscription;
			
			/* Set groups */
			m_Groups.Clear ();
			foreach (jabber.protocol.iq.Group g in item.GetGroups ()) {
				m_Groups.AddLast (g.GroupName);
			}
		}
		
		public Resource GetResource (string name)
		{
			foreach (Resource r in m_Resources)
				if (r.Name == name)
					return r;
			return null;
		}
		
		
		protected Resource CreateResource (string name)
		{
			Resource r = new Resource (name);
			m_Resources.AddFirst (r);
			return r;
		}
		
		///<summary>Update this item's presence info</summary>
		public void Update (jabber.protocol.client.Presence p)
		{
			string rname = p.From.Resource;
			Resource r = GetResource (rname);
			if (r == null) {
				r = CreateResource (rname);
			}
			r.Update (p);
			
			if (StatusChanged != null)
				StatusChanged (this, new StatusChangedEventArgs (r));
		}
		
		/// <summary>
		/// 	Account was disconnected
		/// </summary>
		public void Disconnected ()
		{
			foreach (Resource r in m_Resources) {
				r.Presence = jabber.protocol.client.PresenceType.unavailable;
				r.Show = null;
			}
		}
		#endregion
		
		/* VCard && avatars */
		
		/// <summary>
		/// 	User avatar
		/// </summary>
		public Habazie.kf2.Roster.Avatar Avatar {
			get {
				if (m_Avatar == null)
					m_Avatar = new Habazie.kf2.Roster.Avatar (m_JID);
				return m_Avatar;
			}
		}
		
		
		/// <summary>
		/// 	Contact information
		/// </summary>
		public jabber.protocol.iq.VCard VCard {
			get {
				return m_VCard;
			}
		}
		
		
		/// <summary>
		/// 	Update user info
		/// </summary>
		public void UpdateVCard ()
		{
			Util.Debug ("roster", "Updating user info for {0}", m_JID);
			try {
				jabber.protocol.iq.VCardIQ iq = new jabber.protocol.iq.VCardIQ (Account.Document);
				iq.To = m_JID.Bare;
				iq.Type = jabber.protocol.client.IQType.get;
				Account.Tracker.BeginIQ (iq, VCardRetrieved, null);
			} catch (Exception e) {
				Util.ReportException (e);
			}
		}
		
		
		/// <summary>
		///		Received vcard response
		/// </summary>
		protected virtual void VCardRetrieved (object sender, jabber.protocol.client.IQ iq, object data)
		{
			jabber.protocol.iq.VCard vcard = null;
			try {
				vcard = (jabber.protocol.iq.VCard) iq["vCard"];
			} catch (Exception e) {
				Util.ReportException (e);
			}
			
			if (vcard != null) {
				Gtk.Application.Invoke (delegate {
					ProcessVCard (vcard);
				});
			}
		}
		
		
		/// <summary>
		///		Process vcard response
		/// </summary>
		protected virtual void ProcessVCard (jabber.protocol.iq.VCard vcard)
		{
			m_VCard = vcard;
			
			/* Get an avatar */
			try {
				/* Get PHOTO/BINAVAL element */
				System.Xml.XmlElement el = vcard["PHOTO"];
				string text = el["BINVAL"].InnerText;
				/* Load pixbuf */
				byte [] data = System.Convert.FromBase64String (text);
				m_Avatar.Pixbuf = new Gdk.Pixbuf (data);
				
				// TODO: remove PHOTO from vcard, as it is big and unnecessary
			} catch (Exception e) {
				Util.ReportException (e);
			} finally {
				if (InformationChanged != null)
					InformationChanged (this, new EventArgs ());
			}
		}
	}
	
	public delegate void StatusChangedEventHandler (object sender, StatusChangedEventArgs args);
	
	public class StatusChangedEventArgs : EventArgs
	{
		Resource m_Res;
		
		public StatusChangedEventArgs (Resource r)
		{
			m_Res = r;
		}
		
		public Habazie.kf2.Roster.Resource Resource {
			get { return m_Res; }
		}
	}
}
